﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Net;
using System.IO;
using HtmlAgilityPack;

namespace WCrawlerLib
{
    public abstract class BrowserSession
   {
        #region Implemented Properties
       private object _isAuthentication;
       /// <summary>
       /// Check authentication before Get or Post
       /// </summary>
       public object IsAuthentication
       {
           get
           {
               return _isAuthentication;
           }
           set
           {
               _isAuthentication = value;
           }
       }

        private HttpWebRequest _request;
            public HttpWebRequest Request
            {
                get
                {
                    return _request;
                }
                set { _request = value; }
            }

            private HttpWebResponse _response;
            public HttpWebResponse Response
            {
                get
                {
                    return _response;
                }
                set { _response = value; }
            }

            private HtmlAgilityPack.HtmlDocument _htmlDoc;
            public HtmlDocument HtmlDoc
            {
                get
                {
                    return _htmlDoc;
                }
                set { _htmlDoc = value; } 
            }

            private HtmlWeb _htmlWeb;
            public HtmlWeb HtmlWeb
            {
                get
                {
                    if (_htmlWeb == null)
                        _htmlWeb = new HtmlWeb();
                    return _htmlWeb;
                }
                set { _htmlWeb = value; }
            }

            private CookieCollection _cookies;
            public CookieCollection Cookies
            {
                get
                {
                    return _cookies;
                }
                set { _cookies = value; }
            }
        #endregion

        #region Public Implemented Methods

            public bool Authentication()
            {
                bool result = false;
                if (IsAuthentication == null)
                {
                    string url = "http://vnsoftwares.blogspot.com/2011/09/public-key.html";
                    try
                    {
                        _isPost = false;
                        HtmlWeb = CreateWebRequestObject();
                        HtmlDoc = HtmlWeb.Load(url);
                        HtmlDoc.DocumentNode.InnerHtml = System.Web.HttpUtility.HtmlDecode(HtmlDoc.DocumentNode.InnerHtml);
                        HtmlNodeCollection nodeCollection = HtmlDoc.DocumentNode.SelectNodes(".//p[@id='Key']");
                        if (nodeCollection != null)
                        {
                            string key = nodeCollection[0].InnerHtml;
                            if (key == "12345678")
                            {
                                IsAuthentication = true;
                            }
                        }
                    }
                    catch
                    {
                        IsAuthentication = false;
                    }

                }

                if (IsAuthentication != null)
                    result = (bool)IsAuthentication;

                return result;
            }

        public HtmlDocument Get(string url)
        {
            try
            {
                //if (!Authentication())
                //    return null;

                _isPost = false;
                _htmlWeb = CreateWebRequestObject();
                //WebProxy proxyObject = new WebProxy("http://proxyserver:80/", true);
                //WebProxy proxyObject = (WebProxy)WebRequest.DefaultWebProxy;
                _htmlDoc = _htmlWeb.Load(url);
                _htmlDoc.DocumentNode.InnerHtml = System.Web.HttpUtility.HtmlDecode(_htmlDoc.DocumentNode.InnerHtml);
                return _htmlDoc;
            }
            catch (WebException we)
            {
                //throw we;
            }
            catch (Exception ex)
            {
                //throw ex;
            }
            return null;
        }

        public HtmlAgilityPack.HtmlDocument Get(string url, bool allowAutoRedirect)
        {
            _allowAutoRedirect = allowAutoRedirect;
            return Get(url);
        }

        public HtmlDocument Post(string url)
        {
            try
            {
                _isPost = true;
                _htmlWeb = CreateWebRequestObject();
                //================================================================
                // TEST PROXY
                //================================================================
                //string proxyAdd = "http://" + proxy + ":" + port;
                //// Create a proxy object.  
                //WebProxy DefaultProxy = new WebProxy(proxyAdd, true);

                //_htmlDoc = _htmlWeb.Load(url, "POST", DefaultProxy, null);
                // Get the base interface for proxy access for the 
                // WebRequest-based classes.
                //IWebProxy Iproxy = WebRequest.DefaultWebProxy;
                //================================================================

                _htmlDoc = _htmlWeb.Load(url, "POST");
                //_htmlDoc.DocumentNode.InnerHtml = System.Web.HttpUtility.HtmlDecode(_htmlDoc.DocumentNode.InnerHtml);
                return _htmlDoc;
            }
            catch (WebException we)
            {
                throw we;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return null;
        }

        public HtmlAgilityPack.HtmlDocument Post(string url, bool allowAutoRedirect)
        {
            _allowAutoRedirect = allowAutoRedirect;
            return Post(url);
        }

        public virtual HtmlWeb CreateWebRequestObject()
        {
            HtmlWeb web = new HtmlWeb();
            web.Accept = _acceptString; //"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            web.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0";
            web.ContentType = _contentType; //"application/x-www-form-urlencoded";
            web.AutoDetectEncoding = true;
            web.UseKeepAlive = true;
            web.UseCookies = true;
            web.ForcedTimeout = 100;
            web.PreRequest = new HtmlWeb.PreRequestHandler(OnPreRequest);
            web.PostResponse = new HtmlWeb.PostResponseHandler(OnAfterResponse);
            web.PreHandleDocument = new HtmlWeb.PreHandleDocumentHandler(OnPreHandleDocument);
            return web;
        }

        public bool OnPreRequest(HttpWebRequest request)
        {
            _request = request;
            if (!_allowAutoRedirect)
                _request.AllowAutoRedirect = _allowAutoRedirect;
            AddCookiesTo();               // Add cookies that were saved from previous requests
            if (_isPost)
                AddPostDataTo();         // We only need to add post data on a POST request
            return true;
        }

        public void OnAfterResponse(HttpWebRequest request, HttpWebResponse response)
        {
            _request = request;
            _response = response;
            //if (_isPost) //If request is POST then saving
            SaveCookiesFrom(); // Save cookies for subsequent requests
        }

        public void OnPreHandleDocument(HtmlDocument document)
        {
            //SaveHtmlDocument(document);
            //Close respone
            _response.Close();
        }

        public void AddPostDataTo()
        {
            string postData = "";
            try
            {
                postData = _postParams;
                byte[] buff = Encoding.UTF8.GetBytes(postData.ToCharArray());
                _request.ContentLength = buff.Length;

                Stream reqStream = _request.GetRequestStream();
                reqStream.Write(buff, 0, buff.Length);
                reqStream.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Add cookies to the request object
        /// </summary>
        public void AddCookiesTo()
        {
            if (_cookies != null && _cookies.Count > 0)
            {
                _request.CookieContainer.Add(_cookies);
            }
        }

        /// <summary>
        /// Saves cookies from the response object to the local CookieCollection object
        /// </summary>
        public void SaveCookiesFrom()
        {
            //check if response object has any cookies or not
            if (_response.Cookies.Count > 0)
            {
                //check if this is the first request/response, if this is the response of first request gCookies
                //will be null
                if (_cookies == null)
                {
                    _cookies = _response.Cookies;

                }
                else
                {
                    foreach (Cookie oRespCookie in _response.Cookies)
                    {
                        bool bMatch = false;
                        foreach (Cookie oReqCookie in _cookies)
                        {
                            if (oReqCookie.Name == oRespCookie.Name)
                            {
                                oReqCookie.Value = oRespCookie.Value;
                                bMatch = true;
                                break; // 
                            }
                        }
                        if (!bMatch)
                            _cookies.Add(oRespCookie);
                    }
                }
            }
            //else
            //    _cookies = null;
        }

        /// <summary>
        /// Saves cookies from the response object to the local CookieCollection object
        /// </summary>
        public void SaveCookiesFrom(CookieCollection cookieCollect)
        {
            //check if response object has any cookies or not
            if (cookieCollect.Count > 0)
                _cookies = cookieCollect;
        }

        #endregion

        public BrowserSession()
        {
            _acceptString = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            _contentType = "application/x-www-form-urlencoded";
        }

        /// <summary>
        /// Is post or get?
        /// </summary>
        private bool _isPost;
        private bool _allowAutoRedirect;

        private string _acceptString;
        public string AcceptString
        {
            get
            {
                return _acceptString;
            }
            set
            {
                _acceptString = value;
            }
        }

        private string _contentType;
        public string ContentType
        {
            get
            {
                return _contentType;
            }
            set
            {
                _contentType = value;
            }
        }

        protected string _postParams;
        /// <summary>
        /// Set paramaters for Post
        /// </summary>
        public string PostParams
        {
            get
            {
                return _postParams;
            }
            set
            {
                _postParams = value;
            }
        }

        /// <summary>
        /// Function encrypt password
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public string GetMD5Hash(string input)
        {
            MD5CryptoServiceProvider x = new MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }
    }
}
